// DisplayController.cpp: implementation of the DisplayController class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include <mmsystem.h>
#include <process.h>
#include "flydx9.h"
#include "DisplayController.h"
#include "BaseDispSprite.h"
#include "DataController.h"
#include "GameMap.h"
#include "KeyBoardController.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

#pragma comment(lib, "d3d9.lib")
#pragma comment(lib, "d3dx9.lib")

#define D3D_WIN_CLASS_NAME _T("D3D_WINDOWS_CLASS")

#define WM_LOAD_MAP WM_USER+156
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
LPDIRECT3D9 DisplayController::m_pD3D = NULL;   
LPDIRECT3DDEVICE9 DisplayController::m_pd3dDevice=NULL;
HANDLE DisplayController::m_hThread=NULL;
HWND DisplayController::m_hWnd=NULL;
GameMap* DisplayController::m_pCurrentGameMap=NULL;
map<PicIdx_t,LPDIRECT3DTEXTURE9> DisplayController::m_mapIndexToTex;
POINT DisplayController::ptLastMousePosit;   
POINT DisplayController::ptCurrentMousePosit;   
bool DisplayController::bMousing=false; 
RanderState_e DisplayController::m_eRanderState=eRoom;
DisplayController::DisplayController()
{

}

DisplayController::~DisplayController()
{

}

bool DisplayController::Initialize(HWND hwnd,BOOL bWindowed)
{
	DataController::Initialize();

	m_hWnd=hwnd;
	if(!InitializeD3D(m_hWnd,bWindowed))
	{
		return false;
	}
	if(!BaseDispSprite::Initialize(m_pd3dDevice))
	{
		return false;
	}

	return true;
}
void DisplayController::MsgLoop()
{
	MSG uMsg;   
	memset(&uMsg,0,sizeof(uMsg));   
	while( uMsg.message != WM_QUIT )   
	{   
		if( PeekMessage( &uMsg, NULL, 0, 0, PM_REMOVE ) )   
		{    
			TranslateMessage( &uMsg );
			DispatchMessage( &uMsg );
		}   
		else   
		{
			render(timeGetTime());
		}   
	}   
}
bool DisplayController::InitializeD3D(HWND hwnd,BOOL bWindowed)
{
	m_pD3D = Direct3DCreate9( D3D_SDK_VERSION );
	if(!m_pD3D){
		AfxMessageBox(_T("Direct3DCreate9 failed"));
		return false;
	}
	
	D3DDISPLAYMODE d3ddm;   
    if(D3D_OK!=m_pD3D->GetAdapterDisplayMode( D3DADAPTER_DEFAULT, &d3ddm )){
		AfxMessageBox(_T("GetAdapterDisplayMode failed"));
		return false;
	}
	
    D3DPRESENT_PARAMETERS d3dpp;   
    ZeroMemory( &d3dpp, sizeof(d3dpp));   
	
    d3dpp.Windowed               = bWindowed;   
    d3dpp.SwapEffect             = D3DSWAPEFFECT_DISCARD;   
    d3dpp.BackBufferFormat       = d3ddm.Format;   
    d3dpp.EnableAutoDepthStencil = FALSE;   
    d3dpp.AutoDepthStencilFormat = /*D3DFMT_D16*/D3DFMT_UNKNOWN;
    d3dpp.PresentationInterval   = D3DPRESENT_INTERVAL_ONE;

 	d3dpp.BackBufferWidth=RESOLUTION_x;
 	d3dpp.BackBufferHeight=RESOLUTION_y;
	if (!bWindowed)
	{
		d3dpp.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT; 
	}

    if(D3D_OK!=m_pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hwnd,   
		D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &m_pd3dDevice )){
		AfxMessageBox(_T("CreateDevice failed"));
		return false;
	}

	return true;
}

bool DisplayController::Uninitialize()
{
	m_pCurrentGameMap=NULL;

	map<PicIdx_t,LPDIRECT3DTEXTURE9>::iterator itmap;
	itmap=m_mapIndexToTex.begin();
	for (;itmap!=m_mapIndexToTex.end();itmap++){
		SAFE_RELEASE(itmap->second)
	}
	m_mapIndexToTex.clear();

	PostMessage(m_hWnd,WM_QUIT,0,0);
	DataController::Uninitialize();
	BaseDispSprite::Uninitialize();  
	SAFE_RELEASE(m_pd3dDevice)
	SAFE_RELEASE(m_pD3D)

	return true;
}

void DisplayController::render(DWORD dCurrentTime)
{
	if (!m_pd3dDevice) return;
	HRESULT hr;
	hr=m_pd3dDevice->Clear( 0, NULL, D3DCLEAR_TARGET /*| D3DCLEAR_ZBUFFER*/,   
		D3DCOLOR_COLORVALUE(0.35f, 0.53f, 0.7, 1.0f), 1.0f, 0 );   
	
	hr=m_pd3dDevice->BeginScene();
	switch (m_eRanderState)
	{
	case eBeginPlaying:
		if (m_pCurrentGameMap)
		{
			m_pCurrentGameMap->GameStart(dCurrentTime);
			m_eRanderState=ePlaying;
		}
	case ePlaying:
		if (m_pCurrentGameMap)
		{
			DataController::m_mutexUpdateMap.Lock();
			m_pCurrentGameMap->UpdateAllLgSprite(dCurrentTime);
			hr=BaseDispSprite::Begin( D3DXSPRITE_ALPHABLEND ); 
			m_pCurrentGameMap->DrawAllSprite(dCurrentTime);
			hr=BaseDispSprite::End();   
			DataController::m_mutexUpdateMap.Unlock();
		}
		break;
	case ePlayer:
		break;
	case eRoom:
		break;
	}
	
	hr=m_pd3dDevice->EndScene();   
	hr=m_pd3dDevice->Present( NULL, NULL, NULL, NULL );  

	Sleep(10);
}

bool DisplayController::InitGameMap(GameMap* pGameMap)
{
	m_eRanderState=eRoom;
	DataController::m_mutexUpdateMap.Lock();
	if(m_pCurrentGameMap){
		m_pCurrentGameMap->UnloadTheMap();
	}
	m_pCurrentGameMap=NULL;
	if(!pGameMap->ReadTheMap(m_pd3dDevice))
	{
		DataController::m_mutexUpdateMap.Unlock();
		return false;
	}
	RECT rect={0,0,RESOLUTION_x,RESOLUTION_y};
	DataController::UpdateView(rect);
	m_pCurrentGameMap=pGameMap;
	DataController::m_mutexUpdateMap.Unlock();
	m_eRanderState=eBeginPlaying;
	return true;
}
/*
D3DFORMAT DisplayController::CheckDisplayMode(UINT nWidth, UINT nHeight, UINT nDepth) 
{     
	UINT x;     
	D3DDISPLAYMODE d3ddm;    
	for(x = 0; x < m_pD3D->GetAdapterModeCount(0); x++){   
		m_pD3D->EnumAdapterModes(0, x, &d3ddm);    
		if(d3ddm.Width == nWidth){          
			if(d3ddm.Height == nHeight){       
				if((d3ddm.Format == D3DFMT_R5G6B5)||(d3ddm.Format == D3DFMT_X1R5G5B5)||(d3ddm.Format == D3DFMT_X4R4G4B4)){       
					if(nDepth == 16){   
						return d3ddm.Format;
					}                 
				}else if((d3ddm.Format == D3DFMT_R8G8B8) ||(d3ddm.Format == D3DFMT_X8R8G8B8)){      
					if(nDepth == 32){       
						return d3ddm.Format;
					}                 
				}          
			}        
		}     
	}     
	return D3DFMT_UNKNOWN;
}*/
LPDIRECT3DTEXTURE9 DisplayController::CreateTex(PicIdx_t pt, const Pic_t& stPic)
{
	LPDIRECT3DTEXTURE9 pTexture;
	D3DXIMAGE_INFO d3dxImageInfo;  
	map<PicIdx_t,LPDIRECT3DTEXTURE9>::iterator itmap=m_mapIndexToTex.find(pt);
	if (itmap==m_mapIndexToTex.end()){
		HRESULT hr=D3DXCreateTextureFromFileEx( m_pd3dDevice, _T("balloon\\")+stPic.csFile,   
			stPic.nFrameNum*stPic.nWidth, // I had to set width manually. D3DPOOL_DEFAULT works for textures but causes problems for D3DXSPRITE.   
			stPic.nLine*stPic.nHeight, // I had to set height manually. D3DPOOL_DEFAULT works for textures but causes problems for D3DXSPRITE.   
			1,   // Don't create mip-maps when you plan on using D3DXSPRITE. It throws off the pixel math for sprite animation.   
			D3DPOOL_DEFAULT, D3DFMT_UNKNOWN, D3DPOOL_DEFAULT, D3DX_DEFAULT, D3DX_DEFAULT,   
			D3DCOLOR_COLORVALUE(0.0f,0.0f,0.1f,1.0f), &d3dxImageInfo, NULL, &pTexture );
		if(D3D_OK!=hr){
			switch (hr)
			{
			case D3DERR_OUTOFVIDEOMEMORY:
				break;
			case D3DXERR_INVALIDDATA:
				break;
			case E_OUTOFMEMORY:
				break;
			case D3DERR_NOTAVAILABLE:
				break;
			case D3DERR_INVALIDCALL:
				break;
			}
			return NULL;
		}
		m_mapIndexToTex[pt]=pTexture;
	}else{
		pTexture=m_mapIndexToTex[pt];
	}
	return pTexture;
}